/**
 * 
 */
package com.momosw.games.engine;

import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.momosw.games.engine.player.Player;
import com.momosw.games.jericho.board.Scoring;

/**
 * <b>Project:</b> JerichoCardGame<br />
 * <b>Package:</b> com.momosw.games.engine<br />
 * <b>Class:</b> GameResults.java<br />
 * <br />
 * <i>GSI 2011</i><br />
 *
 * @author Miguel Coronado (miguelcb84@gmail.com)
 * @version	Aug 23, 2011
 *
 */
public class GameResults {

    /** List of scoring phases: source */
    private List<Scoring> scoringPhases;
    /** The amount of points of each player */
    private Map<Player, Integer> results;
    /** The final position of each player */
    private Map<Player, Integer> rank;
    
    /**
     * Constructor
     */
    public GameResults(List<Scoring> scoringPhases) {
        this.scoringPhases = scoringPhases;
        this.results = new HashMap<Player, Integer>();
        this.rank = new HashMap<Player, Integer>();
        
        // Generate results (adding all the scores achieved in the scoring phases) 
        for (Scoring scoring : scoringPhases){
            Map<Player, Integer> auxRes = scoring.getResults();
            for (Player player : auxRes.keySet()) {
                Integer accumulateResult = results.get(player);
                if (accumulateResult == null) {
                    accumulateResult  = 0;
                }
                results.put(player, accumulateResult + auxRes.get(player));
            }
        }
        
        // Generate the rank (by ordering the players)
        Set<Player> reviewed = new HashSet<Player>();
        Set<Player> currentPlayer = new HashSet<Player>(); // esto no es único por si hay empate
        int currentScore = 0;
        for (int index = 0; index < results.size(); index++ ){
            for (Player player : results.keySet()) {
                if (!reviewed.contains(player)) {
                    int score = results.get(player);
                    if(score > currentScore) {
                        currentScore = score;
                        currentPlayer.clear();
                    }
                    if(score >= currentScore ){
                        currentPlayer.add(player);
                    }
                }
            }
            
            for (Player player : currentPlayer) {
                this.rank.put(player, reviewed.size() + 1);
            }
            reviewed.addAll(currentPlayer); // Add reviewed
            currentPlayer.clear();  // Clear locals
            currentScore = 0;
        }
    }
    
    /**
     * 
     */
    public int getNumPlayers() {
        return rank.size();
    }
    
    /**
     * 
     * @param player
     * @return
     */
    public int getRank (Player player) {
        return rank.get(player);
    }
    
    /**
     * Get the player at the specific rank
     * @param rank  The rank
     * @return  The Player
     */
    public Player getPlayerAtRank (int rank) {
        for (Player player : this.rank.keySet()){
            int playersRank = this.rank.get(player);
            if (playersRank == rank) {
                return player;
            }
        }
        return null;
    }
    
    /**
     * 
     * @param player
     * @return
     */
    public int getResults (Player player) {
        return results.get(player);
    }
    
    /**
     * 
     * @return
     */
    public List<Scoring> getScoringPhases () {
        return scoringPhases;
    }
    
    /**
     * Checks if the given player has won the game.
     * @param player the player
     * @return  true if the player won the game.
     */
    public boolean isWinner (Player player){
        return this.rank.get(player) == 1;
    }
    
    public boolean isDrawn() {
        int firsts = 0;
        for (Player player : this.rank.keySet()){
            if (this.rank.get(player) == 1) {
                firsts++;
            }
        }
        return firsts != 1;
    }
    
    /**
     * 
     * @return
     */
    public Set<Player> getPlayers () {
       return rank.keySet(); 
    }
    
    public String toString() {
        return results.toString(); 
    }
    
    public String printSummary () {
        return printSummary(null);
    }
    
    public String printSummary (Player player) {
        if (player == null){
            return results.toString();
        }
        // Print particular results for the given player
        if (isWinner(player)){
            if (isDrawn()){
                return results.toString() + " (0) Draw";
            }
            return results.toString() + " (+" + advantage (player, 2) + ")";
        }
        return results.toString() + " (" + advantage (player, 1) + ") Beaten[" + rank.get(player) + "º]";
    }
    
    private int advantage (Player player, Player overPlayer){
        return this.results.get(player) - this.results.get(overPlayer);
    }
    
    private int advantage (Player player, int overRank) {
        return advantage (player, getPlayerAtRank(overRank));
    }
    
}
